package cc.rengu.igas.cops.core.service.trans.payment;

import cc.rengu.igas.cops.common.enums.RespCodeEnum;
import cc.rengu.igas.cops.core.service.base.ManageService;
import cc.rengu.igas.cops.facade.request.ApplySmsCodeRequest;
import cc.rengu.igas.cops.facade.response.ApplySmsCodeResponse;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.igas.share.common.constant.UserSessionConstant;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.MsgTemplateCfgMapper;
import cc.rengu.oltp.service.common.dao.NonFinanceTxnMapper;
import cc.rengu.oltp.service.common.dao.impl.MsgTemplateCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.NonFinanceTxnMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.MsgTemplateCfg;
import cc.rengu.oltp.service.common.entity.NonFinanceTxn;
import cc.rengu.oltp.service.common.entity.SmsInfo;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.realize.ImageCodeService;
import cc.rengu.oltp.service.realize.TransCustomImpl;
import cc.rengu.oltp.service.realize.impl.ImageCodeServiceImpl;
import cc.rengu.oltp.service.realize.impl.SmsServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.GlobalTransUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class CopsApplySmsCodeService extends ManageService implements TransCustomImpl {
    OrderInfo orderInfo = null;

    @Override
    protected Object bizBeforeCust() throws Exception {
        ApplySmsCodeRequest applySmsCodeRequest = new ApplySmsCodeRequest();
        ConvertUtil.convertOutput(applySmsCodeRequest);
        return applySmsCodeRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {

        BizResponse<ApplySmsCodeResponse> bizResponse = new BizResponse<>();
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);

        ApplySmsCodeRequest applySmsCodeRequest = (ApplySmsCodeRequest) request;
        String instId = applySmsCodeRequest.getHeader().getInstId();
        String phoneNo = applySmsCodeRequest.getPhoneNo();
        String smsType = applySmsCodeRequest.getSmsType();
        String userId = applySmsCodeRequest.getUserId();

        //请求参数合法性检查
        UserService userService = new UserServiceImpl();
        if (StringUtil.isEmptyOrNull(userId) && StringUtil.isEmptyOrNull(phoneNo)) {
            rglog.error("用户标识<{}>及手机号<{}>二者必须上送一个!", userId, phoneNo);
            throw new BizException(RespCodeEnum.PARAM_ERROR.getRespCode(), RespCodeEnum.PARAM_ERROR.getRespDesc());
        }

        /* 若上传userId则校验用户是否存在，用户存在且当前交易上传了phone则比对用户手机号与上传的手机号是否一致(修改手机号交易不做比对) */
        if (StringUtil.isEmptyOrNull(userId) && !SmsTypeEnum.CARD_SIGN.getSmsType().equals(smsType) && !SmsTypeEnum.MODIFY_PHONE.getSmsType().equals(smsType)) {
            //获取用户信息
            UserInfo userInfo = userService.getUserInfo(instId, userId, applySmsCodeRequest.getHeader().getSession());
            if (null == userInfo) {
                rglog.info("用户信息不存在且未上传用户标识");
                throw new BizException(RespCodeEnum.USER_NOT_EXIT_ERROR.getRespCode(), RespCodeEnum.USER_NOT_EXIT_ERROR.getRespDesc());
            }
            if (StringUtil.isEmptyOrNull(phoneNo)) {
                rglog.info("当前交易未上送手机号，使用用户预留手机号:<{}>", phoneNo);
                phoneNo = userInfo.getMobileNo();
            } else if (!userInfo.getMobileNo().equals(phoneNo)) {
                if (SmsTypeEnum.SET_PASSWORD.getSmsType().equals(smsType) || SmsTypeEnum.RESET_PASSWORD.getSmsType().equals(smsType) ||
                        SmsTypeEnum.MODIFY_PASSWORD.getSmsType().equals(smsType) || SmsTypeEnum.FAST_PAYMENT.getSmsType().equals(smsType)) {
                    rglog.info("当前用户手机号<{}>和输入手机号<{}>不一致", userInfo.getMobileNo(), phoneNo);
                    throw new BizException(RespCodeEnum.MOBILE_DIFERENT.getRespCode(), RespCodeEnum.MOBILE_DIFERENT.getRespDesc());
                } else {
                    rglog.info("当前用户手机号<{}>和输入手机号<{}>不一致", userInfo.getMobileNo(), phoneNo);
                    throw new BizException(RespCodeEnum.MOBILE_DIFERENT.getRespCode(), RespCodeEnum.MOBILE_DIFERENT.getRespDesc());
                }
            }
        }
        List<String> phoneNoList = new ArrayList<>();
        phoneNoList.add(phoneNo);
        GlobalTransUtil.setCacheValue(TransCacheConstant.SMS_PHONE_NO_LIST, phoneNoList);

        // 获取短信模板枚举类型
        TemplateTypeEnum templateTypeEnum = SmsTypeEnum.getTemplateTypeEnum(smsType);
        if (null == templateTypeEnum) {
            rglog.error("不支持的验证码类型!");
            throw new BizException(RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), RespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else if (TemplateTypeEnum.SMS_MODIFY_MOBILE_NUMBER.equals(templateTypeEnum)) {
            /* 修改用户手机号发送短信前先验证用户身份认证是否成功 */
            String identityVerifySeqNum = userService.getUserSessionValue(UserSessionConstant.IDENTITY_VERIFY_SEQ_NUM);
            if (StringUtil.isEmptyOrNull(identityVerifySeqNum)) {
                rglog.error("在用户会话缓存中获取用户手机号身份认证流水号失败,在设置新手机号页面中不允许发送短信!");
                throw new BizException(RespCodeEnum.AUTHCODE_EXPR_ERROR.getRespCode(), RespCodeEnum.AUTHCODE_EXPR_ERROR.getRespDesc());
            }
            NonFinanceTxnMapper nonFinanceTxnMapper = new NonFinanceTxnMapperImpl();
            NonFinanceTxn nonFinanceTxn = nonFinanceTxnMapper.selectNonFinanceTxnInfoByPrimaryKey(applySmsCodeRequest.getHeader().getInstId(), identityVerifySeqNum);
            if (null == nonFinanceTxn || !TransStatusEnum.TRANS_SUCC.getStatus().equals(nonFinanceTxn.getTxnStatus())) {
                rglog.error("修改用户手机号身份认证失败,在设置新手机号页面中不允许发送短信!");
                throw new BizException(RespCodeEnum.AUTHCODE_EXPR_ERROR.getRespCode(), RespCodeEnum.AUTHCODE_EXPR_ERROR.getRespDesc());
            }
        }

        //获取短信模板
        MsgTemplateCfgMapper msgTemplateCfgMapper = new MsgTemplateCfgMapperImpl();
        MsgTemplateCfg msgTemplateCfg = msgTemplateCfgMapper.selectMsgTemplateCfgByTemplateType(instId, templateTypeEnum.getTemplateType());
        if (null == msgTemplateCfg) {
            msgTemplateCfg = msgTemplateCfgMapper.selectMsgTemplateCfgByTemplateType(AppParamConstant.DEFAULT_INSTID, templateTypeEnum.getTemplateType());
            if (null == msgTemplateCfg) {
                rglog.error("未配置短信发送模板!");
                throw new BizException(RespCodeEnum.NOT_CONF_MSG_TEMPLATE.getRespCode(), RespCodeEnum.NOT_CONF_MSG_TEMPLATE.getRespDesc());
            }
        }
        rglog.debug("短信模板代码:<{}>,短信模板内容:<{}>", msgTemplateCfg.getTemplateCode(), msgTemplateCfg.getTemplateDesc());
        GlobalTransUtil.setCacheValue(TransCacheConstant.SMS_TEMPLATE_CODE, msgTemplateCfg.getTemplateCode());

        //校验图形验证码
        ImageCodeService imageCodeService = new ImageCodeServiceImpl();
        boolean imageVerifyFlag = imageCodeService.verifyImageCode(instId, applySmsCodeRequest.getImageAuthCodeSeqNum(), applySmsCodeRequest.getImageAuthCode());
        if (!imageVerifyFlag) {
            rglog.error("图片验证码校验失败!");
            throw new BizException(RespCodeEnum.VERIFICATION_CODE_INVALID.getRespCode(), RespCodeEnum.VERIFICATION_CODE_INVALID.getRespDesc());
        }

        //生成短信验证码
        rglog.debug("用户用于获取短信验证码的手机号:<{}>", phoneNo);
        SmsServiceImpl smsService = new SmsServiceImpl();
        SmsInfo smsInfo = smsService.generateSmsCode(instId, phoneNo, smsType);
        if (smsInfo == null) {
            rglog.info("生成短信验证码失败");
            throw new BizException(RespCodeEnum.GEN_CHECK_CODE_FAIL.getRespCode(), RespCodeEnum.GEN_CHECK_CODE_FAIL.getRespDesc());
        }
        String smsContent = parseSmsTemplateInfo(msgTemplateCfg.getTemplateDesc(), smsInfo.getSmsCode());
        GlobalTransUtil.setCacheValue(TransCacheConstant.SMS_CONTENT, smsContent);

        //获取通道调用配置，调用业务支撑通道发送短信
        Optional<ChannelCallCfg> channelCallCfgOpt = txnInfo.getChannelCallCfgList().stream().filter(item ->
                item.getCallIndex().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX) &&
                        item.getCallChannelId().equals(ChannelEnum.SMPS.getChannelType())).findFirst();
        if (!channelCallCfgOpt.isPresent()) {
            rglog.error("未配置通道的通道服务调用配置,txnKey:<{}>,msgDstId:<{}>", txnInfo.getTxnKey(), ChannelEnum.ESB.getChannelType());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        ChannelCallCfg channelCallCfg = channelCallCfgOpt.get();
        Class channelClasz = Class.forName(channelCallCfg.getCallChannelImpl());
        ChannelBaseService channelBaseService = (ChannelBaseService) channelClasz.newInstance();
        channelBaseService.callService(txnInfo, (null == orderInfo) ? new OrderInfo() : orderInfo, channelCallCfg.getBizScene(), request);

        //短信验证码验证流水号存入用户会话缓存中
        userService.setUserSessionValue(UserSessionConstant.SMS_VERIFY_SEQ_NUM, smsInfo.getVerifySeqNum());

        //设置响应内容
        ApplySmsCodeResponse applySmsCodeResponse = new ApplySmsCodeResponse();
        applySmsCodeResponse.setPhoneNo(phoneNo);
        applySmsCodeResponse.setSmsVerifySeqNum(smsInfo.getVerifySeqNum());
        bizResponse.setResult(applySmsCodeResponse);
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        ApplySmsCodeResponse applySmsCodeResponse = (ApplySmsCodeResponse) bizResponse.getResult();
        ConvertUtil.convertInput(applySmsCodeResponse);
    }

    /**
     * 动态解析短信模板生成短信内容
     *
     * @param templateDesc 短信模板内容
     * @param smsCode      短信验证码
     * @return 短信内容
     * @throws Exception 异常
     */
    private String parseSmsTemplateInfo(String templateDesc, String smsCode) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        StringBuilder stringBuilder = new StringBuilder();
        while (!StringUtil.isEmptyOrNull(templateDesc) && templateDesc.contains("[")) {
            int startIndex = templateDesc.indexOf("[");
            stringBuilder.append(templateDesc, 0, startIndex);
            templateDesc = templateDesc.substring(startIndex + 1);
            int endIndex = templateDesc.indexOf("]");
            String key = templateDesc.substring(0, endIndex);
            if ("smsCode".equals(key)) {
                stringBuilder.append(smsCode);
            } else if ("sysId".equals(key.trim())) {
                stringBuilder.append("线上收银台");
            } else {
                String value = xmlTreeUtil.getXmlTreeStringValue(key.trim());
                if (null == value) {
                    rglog.error("根据动态模板获取字段值失败,key:<{}>", key);
                    throw new BizException(RespCodeEnum.GEN_CHECK_CODE_FAIL.getRespCode(), RespCodeEnum.GEN_CHECK_CODE_FAIL.getRespDesc());
                } else {
                    //账号脱敏
                    if ("signAcctNo".equals(key.trim())) {
                        stringBuilder.append(value.substring(value.length() - 4));
                    } else {
                        stringBuilder.append(value);
                    }
                }
            }
            templateDesc = templateDesc.substring(endIndex + 1);
        }
        stringBuilder.append(templateDesc);
        return stringBuilder.toString();
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        List<ChannelCallCfg> channelCallCfgs = channelCallCfgList.stream().filter(item -> item.getBizScene().equals(ChannelBaseService.FIRST_CHANNEL_CALL_INDEX)).collect(Collectors.toList());
        return channelCallCfgs.stream().findFirst().orElse(null);
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        return null;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        return transStatusEnum;
    }
}
